import ky, { HTTPError } from 'ky';
import type { Options, ResponsePromise } from 'ky';
import ApiError from './ApiError';

type SentOpts = {
  path: string;
  searchParams?: Record<string, string | number>;
  body?: unknown;
};

const timeout = 10000;

type KyHandler = (url: string, options?: Options | undefined) => ResponsePromise;

const HANDLERS: Record<HttpMethod, KyHandler> = {
  GET: ky.get,
  POST: ky.post,
  PATCH: ky.patch,
  DELETE: ky.delete,
};

async function send<T>(method: HttpMethod, { path, searchParams, body }: SentOpts): Promise<T> {
  const handler = HANDLERS[method];
  if (!handler) {
    throw new Error(`Unsupported method ${method}`);
  }

  try {
    return (await handler(path, { searchParams, json: body, timeout }).json()) as T;
  } catch (err) {
    return await handleError(method, path, err);
  }
}

export const get = <T>(opts: SentOpts) => send<T>('GET', opts);
export const post = <T>(opts: SentOpts) => send<T>('POST', opts);
export const patch = <T>(opts: SentOpts) => send<T>('PATCH', opts);
export const del = <T>(opts: SentOpts) => send<T>('DELETE', opts);

async function handleError(method: string, path: string, err: unknown): Promise<never> {
  if (err instanceof HTTPError) {
    const body = (await err.response.json()) as { msg: string; code: string; payload?: unknown };
    switch (err.response.status) {
      case 400: {
        throw new ApiError('参数错误。快打前端开发的屁股。', 'CLIENT_ERROR');
      }
      case 500: {
        console.error('接口错误', { method, path, err });
        throw new ApiError('服务器错误。快打后端开发的屁股。', 'SERVER_ERROR');
      }
      case 501: {
        throw new ApiError(body.msg, 'BIZ_ERROR');
      }
      case 401: {
        throw new ApiError(body.msg, 'BIZ_ERROR');
      }
      case 403: {
        throw new ApiError(body.msg, 'BIZ_ERROR');
      }
    }
  }
  console.error('接口未知错误', { method, path, err });
  throw new ApiError('未知错误', 'UNKNOWN_ERROR');
}
